Skip to content

feat(sdk): add external sink#175

Open
namrataghadi-galileo wants to merge 14 commits intomainfrom
feature/62793-add-external-sink
Open

feat(sdk): add external sink#175
namrataghadi-galileo wants to merge 14 commits intomainfrom
feature/62793-add-external-sink

Conversation

@namrataghadi-galileo
Copy link
Copy Markdown
Contributor

Summary

Added a vendor-neutral external control-event sink registration API in the Python SDK so integrations can receive finalized ControlExecutionEvent payloads without adding vendor-specific logic to OSS.

Updated observability delivery so observability_enabled is the master gate, and when enabled the SDK uses registered sinks if present, otherwise the existing default OSS batcher sink.

Added docs and test coverage for sink registration, override behavior, fallback to default delivery, and local/server/merged event delivery parity.

Scope

User-facing/API changes:

  • Added register_control_event_sink(...), unregister_control_event_sink(...), and get_registered_control_event_sinks(...) to the Python SDK public API
  • Documented how external integrations can register a sink

Internal changes:

  • Added active sink resolution in the SDK observability layer
  • Enforced observability_enabled before any sink delivery occurs
  • Preserved existing event construction flow for local, server, merged, and partial/error cases
  • Added mock-sink tests covering override semantics and delivery behavior

Out of scope:

  • Config-driven sink selection for SDK/server
  • OTEL sink implementation and configuration
  • Server-side sink resolution changes

Risk and Rollout

Risk level: medium

Rollback plan: Revert the SDK observability sink-resolution changes and public sink registration API additions in the Python SDK. Since default OSS delivery remains the fallback when no external sink is registered, rollback is isolated to the SDK observability layer.

Testing

  • Added or updated automated tests
  • Ran make check — focused validation was run instead. Full workspace checks were unnecessary for this scoped SDK change. There is also a pre-existing unrelated SDK typecheck issue around google.adk untyped imports.
  • Manually verified behavior

Checklist

  • Linked issue/spec (if applicable)
  • Updated docs/examples for user-facing changes
  • Included any required follow-up tasks

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 16, 2026

Codecov Report

❌ Patch coverage is 94.87179% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
sdks/python/src/agent_control/observability.py 94.87% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@lan17 lan17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the direction here, but I don't think this base PR is ready to merge yet. The main thing I'd fix first is the enabled= override becoming sticky process state. I also think we need an explicit lifecycle/ownership story for external sinks before we merge the base abstraction.


# Check if enabled
is_enabled = enabled if enabled is not None else get_settings().observability_enabled
if enabled is not None:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes enabled= from a per-call override into a process-wide mutation. After one init(..., observability_enabled=False), later init/re-init flows and later sink resolution stay disabled until something explicitly rewrites settings. I don't think we want an init-time override to poison the rest of the process like that.

"""Register an external control-event sink.

Registered sinks receive the same finalized control-event payloads emitted
through the SDK's local, server, and merged event flows. When one or more
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we expose caller-registered sinks here, we also need a lifecycle story for them. Right now shutdown still only drains the built-in batcher, so any buffered or networked external sink can still drop data on process exit. I'd rather make ownership explicit here before we merge the base API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants